/**
 *  \file window.hpp
 *  \brief Curses++ window declaraions
 *
 *  This is the only header file you should need to include for the entire
 *  library.
 *
 *  \if LICENSE
 *  Curses++ - Free C++ wrapper to the curses library.
 *  Copyright (C) 2007 Sean Hunt
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *  \endif
 */

#include <cursesplusplus/string.hpp>

namespace curses {
	/// An input keycode.
	namespace key
	{
		/// Hack to acheive scoped enums
		enum code {
			a = 'a',
			b = 'b',
			c = 'c',
			d = 'd',
			e = 'e',
			f = 'f',
			g = 'g',
			h = 'h',
			i = 'i',
			j = 'j',
			k = 'k',
			l = 'l',
			m = 'm',
			n = 'n',
			o = 'o',
			p = 'p',
			q = 'q',
			r = 'r',
			s = 's',
			t = 't',
			u = 'u',
			v = 'v',
			w = 'w',
			x = 'x',
			y = 'y',
			z = 'z',
	
			A = 'A',
			B = 'B',
			C = 'C',
			D = 'D',
			E = 'E',
			F = 'F',
			G = 'G',
			H = 'H',
			I = 'I',
			J = 'J',
			K = 'K',
			L = 'L',
			M = 'M',
			N = 'N',
			O = 'O',
			P = 'P',
			Q = 'Q',
			R = 'R',
			S = 'S',
			T = 'T',
			U = 'U',
			V = 'V',
			W = 'W',
			X = 'X',
			Y = 'Y',
			Z = 'Z',
	
			zero = '0',
			one = '1',
			two = '2',
			three = '3',
			four = '4',
			five = '5',
			six = '6',
			seven = '7',
			eight = '8',
			nine = '9',
	
			space = ' ',
			tab = '\t',
			vertical = '\v',
			alarm = '\a',
			form_feed = '\f',
			backspace = '\b',
			newline = '\n',
	
			underscore = '_',
			left_brace = '{',
			right_brace = '}',
			left_bracket = '[',
			right_bracket = ']',
			hash = '#',
			left_paren = '(',
			right_paren = ')',
			less_than = '<',
			greater_than = '>',
			percent = '%',
			colon = ':',
			semicolon = ';',
			period = '.',
			question = '?',
			asterisk = '*',
			plus = '+',
			minus = '-',
			slash = '/',
			caret = '^',
			ampersand = '&',
			bar = '|',
			tilde = '~',
			exclamation = '!',
			equals = '=',
			comma = ',',
			backslash = '\\',
			double_quote = '"',
			single_quote = '\'',
	
			// "break" is a keyword
			break_key,
			down,
			up,
			left,
			right,
			home,
			delete_line,
			insert_line,
			delete_character,
			insert_character,
			exit_insert_mode,
			clear,
			clear_end_screen,
			clear_end_line,
			scroll_forward,
			scroll_backward,
			page_forward,
			page_backward,
			set_tab,
			clear_tab,
			clear_all_tabs,
			enter,
			soft_reset,
			reset,
			print,
			home_bottom,
	
			keypad_top_left,
			keypad_top = up,
			keypad_top_right,
			keypad_left = left,
			keypad_middle,
			keypad_right = right,
			keypad_bottom_left,
			keypad_bottom = down,
			keypad_bottom_right,

			no_input,
			eof
		};
	};

	/// The keycode type.
	typedef key::code keycode;

	/// Window class.
	/**
	 *  Most %curses functions are interfaced through this class. You cannot
	 *  construct it directly - all windows must be obtained through member
	 *  functions (except via a copy constructor - which just copies stuff).
	 */
	class window {
		private:
			struct priv_data;
			priv_data * data;

			window();
		public:
			/// Output some text to the window at a set of coordinates
			/**
			 *  \param text Text to print.
			 *  \param x X-position at which to display text.
			 *  \param y Y-position at which to display text.
			 *
			 *  When written to the window, the text will word-wrap. Color
			 *  data is preserved. The cursor's position will be updated to
			 *  just past the text.
			 */
			void print (const string& text, unsigned int x, unsigned int y);

			/// Output some text to the window at the current position
			/**
			 *  \param text Text to print.
			 *
			 *  Print the text at the point of the cursor. The text will wrap,
			 *  and the cursor will
			 *  me moved just past the end of the text.
			 */
			void print (const string& text);

			/// Clear the window.
			/**
			 *  The window will return to default construction. You must still
			 *  call update().
			 */
			void clear ();

			/// Update the window for display.
			/**
			 *  This must be called for any changes to be reflected onscreen.
			 */
			void update ();

			/// Retrieve the character at the cursor.
			/**
			 *  This includes all attributes and color data.
			 */
			character get();

			/// Retrieve the displayed character at a specific point.
			/**
			 *  \param x The X-position to retrieve from.
			 *  \param y The Y-position to retrieve from.
			 *  The cursor position is unaffected.
			 */
			character get (unsigned int x, unsigned int y);

			/// Set the cursor position.
			/**
			 *  \param x The X-position to move to.
			 *  \param y The Y-position to move to.
			 *  The cursor position is not unaffected.
			 */
			void move_cursor (unsigned int x, unsigned int y);

			/// Get the cursor position.
			/**
			 *  \param x The variable which will store the X-position.
			 *  \param y The variable which will store the Y-position.
			 */
			void get_cursor (unsigned int& x, unsigned int& y);

			/// Hide the cursor completely.
			static void hide_cursor ();

			/// Put the cursor at normal visibility.
			static void show_cursor ();

			/// Put the cursor at maximal visibility.s
			static void bright_cursor ();

			/// Delete one specific character.
			/**
			 *  \param x The X-coordinate to delete at.
			 *  \param y The Y-coordinate to delete at.
			 *  The character is replaced with a blank, and the cursor is
			 *  unaffected.
			 */
			void del (unsigned int x, unsigned int y);

			/// Pause curses temporarily.
			/**
			 *  This causes curses to halt until such a time as udate is called.
			 *  Normal terminal functionality is restored.
			 */
			static void pause ();

			/// Create a new subwindow.
			/**
			 *  \param x X-coordinate of the top-left of new window.
			 *  \param y Y-coordinate of the top-left of new window.
			 *  \param w Width of new window.
			 *  \param h Height of new window.
			 *  This creates a window that is a subwindow of the current window.
			 *  The subwindow must be completely contained within this window,
			 *  or else Bad Things will happen (a crash, in all likelihood).
			 *  You also can't update two overlapping windows, or else
			 *  Not-Quite-As-Bad Things will happen.
			 */
			window subwin (unsigned int x, unsigned int y, unsigned int w, unsigned int h);

			/// Copy constructor
			window (const window&);

			/// RAAGH! SMASH! DESTROY!
			/**
			 *  The last instance of the main window will end the program -
			 *  undefined behavior will occur if a subwindow is used after
			 *  the main window exits.
			 */
			~window ();

			/// A couple of window options.
			/**
			 *  echo, line_bugger, flush_interrupt, and newline are all global
			 *  - you cannot set them for one window only. These all default to
			 *  being off.
			 */
			typedef unsigned char attribute;
			/// Characters input should be echoed to the screen.
			static const attribute echo = 1 << 0;
			/// Input should wait for a full line, rather than immediate input.
			static const attribute line_buffer = 1 << 1;
			/// The keypad should be recognized as useable.
			static const attribute keypad = 1 << 2;
			/// The input stream should be flushed upon receipt of an interrupt.
			static const attribute flush_interrupt = 1 << 3;
			/// Input should be translated from a carriage return to a newline.
			static const attribute newline = 1 << 4;

			/// Set the attributes for this window.
			void set_attrs (attribute attr);

			/// Get input (yay).
			keycode get_key();

			/// Create a new application window and init curses.
			static window start (const attribute attr = 0);
	};
}
